package br.com.NoTraffic.com;

import java.io.InputStream;
import java.io.OutputStream;

import javax.comm.CommPortIdentifier;
import javax.comm.SerialPort;
import javax.comm.SerialPortEvent;
import javax.comm.SerialPortEventListener;

public class SComm implements Runnable, SerialPortEventListener {
	private String Porta;
	public String Dadoslidos;
	public int nodeBytes;
	private int baudrate;
	private int timeout;
	private CommPortIdentifier cp;
	private SerialPort porta;
	private OutputStream saida;
	private InputStream entrada;
	private Thread threadLeitura;

	private byte[] receivedBytes;
	private boolean IDPortaOK;
	private boolean PortaOK;
	private boolean dadosRecebidos = false;

	public SComm() {
		Porta = "COM1";
		baudrate = 9600;
		timeout = 1500;
	};

	public SComm(String p, int b, int t) {
		this.Porta = p;
		this.baudrate = b;
		this.timeout = t;
	};

	public boolean AbrirPorta() {
		ObterIdDaPorta();
		try {
			porta = (SerialPort) cp.open("SComm", timeout);
			PortaOK = true;
			System.out.println("Porta aberta com sucesso!");

			porta.setSerialPortParams(baudrate, porta.DATABITS_8,
					porta.STOPBITS_1, porta.PARITY_NONE);

			porta.setFlowControlMode(porta.FLOWCONTROL_NONE);
			porta.setRTS(false);
			porta.setDTR(false);
			return true;

		} catch (Exception e) {
			PortaOK = false;
			System.out.println("Erro ao abrir a porta! STATUS: " + e);

			return false;
		}
	}

	public void SendFrame(byte[] msg) {
		try {
			saida = porta.getOutputStream();
		} catch (Exception e) {
			System.out.println("Erro! " + e);
		}
		try {
			// System.out.println("Enviando : " + msg);

			/*
			 * System.out.print("Mensagem enviada: ["); for (int k = 0; k < 8;
			 * k++) { System.out.print(+msg[k] + " "); }
			 * System.out.println("]");
			 */

			saida.write(msg);
			Thread.sleep(100);
			saida.flush();
		} catch (Exception e) {
			System.out.println("Houve um erro durante o envio. ");
			System.out.println("STATUS: " + e);
			System.exit(1);
		}
	}

	public byte[] getReply() {
		dadosRecebidos = false;
		try {
			entrada = porta.getInputStream();
		} catch (Exception e) {
			System.out.println("Erro! " + e);
			this.FecharCom();
		}
		try {
			porta.addEventListener(this);
			// System.out.println("Porta aguardando...");
		} catch (Exception e) {
			System.out.println("Erro ao criar listener: ");
			System.out.println("STATUS: " + e);
			this.FecharCom();

		}

		porta.notifyOnDataAvailable(true);

		try {
			threadLeitura = new Thread(this);
			threadLeitura.start();
		} catch (Exception e) {
			System.out.println("Erro ao iniciar leitura: " + e);
			this.FecharCom();
		}
		do {

		} while (!dadosRecebidos);

		porta.removeEventListener();
		return receivedBytes;
	}

	public void run() {

		try {
			Thread.sleep(700);
			receivedBytes = null;
			dadosRecebidos = true;

		} catch (Exception e) {
			System.out.println("Erro. Status = " + e);
		}
	}

	public void serialEvent(SerialPortEvent ev) {
		switch (ev.getEventType()) {
		case SerialPortEvent.BI:
		case SerialPortEvent.OE:
		case SerialPortEvent.FE:
		case SerialPortEvent.PE:
		case SerialPortEvent.CD:
		case SerialPortEvent.CTS:
		case SerialPortEvent.DSR:
		case SerialPortEvent.RI:
		case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
			break;
		case SerialPortEvent.DATA_AVAILABLE:
			threadLeitura.stop();
			byte[] bufferLeitura = new byte[100];
			receivedBytes = null;
			nodeBytes = 0;
			try {
				while (entrada.available() > 0) {
					nodeBytes = entrada.read(bufferLeitura);
				}
				String Dadoslidos = new String(bufferLeitura);
				if (bufferLeitura.length == 0) {
					System.out.println("Nada lido!");
				} else {

					// receivedBytes = bufferLeitura;
					receivedBytes = new byte[nodeBytes];

					// System.out.print("Mensagem recebida: [");
					for (int i = 0; i < nodeBytes; i++) {
						receivedBytes[i] = bufferLeitura[i];
						// System.out.print(+receivedBytes[i] + " ");
					}
					// System.out.println("]");
					System.out.println("");
					dadosRecebidos = true;

				}
			} catch (Exception e) {
				System.out.println("Erro durante a leitura: " + e);
			}

			// System.out.println("Bytes lidos " + nodeBytes);
			break;
		}
	}

	public void FecharCom() {
		try {
			Thread.sleep(100);
			porta.close();
			System.out.println("Conex�o finalizada!");
		} catch (Exception e) {
			System.out.println("Erro ao finalizar conex�o: " + e);
			System.exit(0);
		}
	}

	public String obterPorta() {
		return Porta;
	}

	public int obterBaudrate() {
		return baudrate;
	}

	private void ObterIdDaPorta() {
		try {
			cp = CommPortIdentifier.getPortIdentifier(Porta);
			if (cp == null) {
				System.out.println("A " + Porta + " nao existe!");
				System.out.println("ERRO!Abortando...");
				IDPortaOK = false;
				System.exit(1);
			}
			IDPortaOK = true;
		} catch (Exception e) {
			System.out.println("Erro durante o procedimento. STATUS" + e);
			IDPortaOK = false;
			System.exit(1);
		}
	}

	public byte[] getReceivedBytes() {
		return receivedBytes;
	}

	public void setReceivedBytes(byte[] receivedBytes) {
		this.receivedBytes = receivedBytes;
	}

	public char doCRC(byte[] pMsg, int MsgLength, int append) {
		char CRCvalue = 0xFFFF, // CRCvalue initialised with all '1's
		i, k = 0; // Loop Control

		while ((MsgLength--) != 0) // Loop until all bytes
		// calculated
		{
			CRCvalue = (char) (CRCvalue ^ (pMsg[k]));
			k++;

			for (i = 0; i++ < 8;) // Shift all 8-bits
			{
				if ((CRCvalue & 0x0001) != 0)
					CRCvalue = (char) ((CRCvalue >> 1) ^ 0xA001);
				else
					CRCvalue >>= 1;
			}
		}

		if (append != 0) {
			// *pMsg = CRCvalue >> 8; // Low byte
			// pMsg++;
			// *pMsg = CRCvalue >> 8; // High byte
		}
		System.out.println("CRC calculado: " + CRCvalue);
		return CRCvalue;
	}
}
